﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#ifndef __XOSKIT_XOS_CORE_XOS_STL_SRC_PROTOCOL_IMPL_PROTOCOL_FIELD_H__
#define __XOSKIT_XOS_CORE_XOS_STL_SRC_PROTOCOL_IMPL_PROTOCOL_FIELD_H__

#include "public_base.h"

namespace xos_protocol
{

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 
    template< class T, class PACKER >
    class public_field : public public_base
    {
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        typedef public_base BASE;
        enum enumField
        {
            FIELD_NUM = 64
        };
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        public_field( xos_box::i_serial * pSerial, xos_box::i_buf * pBuf ) :
            BASE( pSerial, pBuf )
        {
            for( unsigned int i = 0; i < sizeof( fields ) / sizeof( fields[0] ); ++i )
            {
                fields[i] = 0;
            }
            field_num = 0;

            page_size = 0;
            page_num = 0;
            cur_page = 0;

            total_num = 0;
            this_num = 0;
        }
        ~public_field()
        {
        }
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        xos::xos_u8 fields[FIELD_NUM];
        xos::xos_u8 field_num;

        xos::xos_u16 page_size;
        xos::xos_u16 page_num;
        xos::xos_u16 cur_page;

        xos::xos_u32 total_num;
        xos::xos_u16 this_num;
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int req_compose( int nCookie, int nCmd )
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::req_compose( nCookie, nCmd );
            }
            if( 0 == ret )
            {
                ret = pack_field();
            }
            return ret;
        }
        int req_dis_compose()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::req_dis_compose();
            }
            if( 0 == ret )
            {
                ret = un_pack_field();
            }
            return ret;
        }
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int res_compose( int nCookie, int nCmd, int nRet )
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::res_compose( nCookie, nCmd, nRet );
            }
            if( ( 0 == ret ) && ( 0 == nRet ) )
            {
                ret = pack_field();
            }
            return ret;
        }
        int res_dis_compose( int & nRet )
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::res_dis_compose( nRet );
            }
            if( ( 0 == ret ) && ( 0 == nRet ) )
            {
                ret = un_pack_field();
            }
            return ret;
        }
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int set_fields_by_data( T * pT )
        {
            int ret = 0;
            if( 0 == ret )
            {
                field_num = 0;
            }
            for( xos::xos_u8 i = 0; ( 0 == ret ) && pT && ( i < T::FIELD_NUM ); ++i )
            {
                if( !pT->get_use( i ) )
                {
                    continue;
                }
                fields[field_num++] = i;
            }
            return ret;
        }
        int get_fields_to_data( T * pT )
        {
            int ret = 0;
            if( ( 0 == ret ) && !pT )
            {
                ret = 1;
            }
            if( 0 == ret )
            {
                pT->clear_use();
            }
            for( xos::xos_u8 i = 0; ( 0 == ret ) && ( i < field_num ); ++i )
            {
                pT->set_use( i, true );
            }
            return ret;
        }
        int set_fields( xos::xos_u8 num, xos::xos_u8 * pFields )
        {
            int ret = 0;
            if( 0 == ret )
            {
                field_num = 0;
            }
            for( xos::xos_u8 i = 0; ( 0 == ret ) && ( i < num ); ++i )
            {
                fields[i] = pFields[i];
            }
            if( 0 == ret )
            {
                field_num = num;
            }
            return ret;
        }
        int get_fields( xos::xos_u8 & num, xos::xos_u8 * pFields )
        {
            int ret = 0;
            for( xos::xos_u8 i = 0; ( 0 == ret ) && ( i < field_num ); ++i )
            {
                pFields[i] = fields[i];
            }
            if( 0 == ret )
            {
                num = field_num;
            }
            return ret;
        }
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int un_pack_field()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = un_pack_int8( &field_num );
            }
            for( xos::xos_u8 i = 0; ( 0 == ret ) && ( i < field_num ); ++i )
            {
                ret = un_pack_int8( &fields[i] );
            }
            return ret;
        }
        int pack_field()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = pack_int8( field_num );
            }
            for( xos::xos_u8 i = 0; ( 0 == ret ) && ( i < field_num ); ++i )
            {
                ret = pack_int8( fields[i] );
            }
            return ret;
        }
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int un_pack_page()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::un_pack_int16( &page_size );
            }
            if( 0 == ret )
            {
                ret = BASE::un_pack_int16( &page_num );
            }
            if( 0 == ret )
            {
                ret = BASE::un_pack_int16( &cur_page );
            }
            return ret;
        }
        int pack_page()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::pack_int16( page_size );
            }
            if( 0 == ret )
            {
                ret = BASE::pack_int16( page_num );
            }
            if( 0 == ret )
            {
                ret = BASE::pack_int16( cur_page );
            }
            return ret;
        }
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int dis_compose_list_data( typename T::LIST * pList )
        {
            int ret = 0;
            for( xos::xos_u16 i = 0; ( 0 == ret ) && ( i < this_num ); ++i )
            {
                T * pT = T::get_item_from_pool( true );
                pT->init();
                ret = un_pack_data( pT );
                if( 0 == ret )
                {
                    if( pList )
                    {
                        pList->push_back( pT );
                    }
                    else
                    {
                        PACKER::push( pT );
                    }
                    pT = 0;
                }
                xos_stl::release_interface( pT );
            }
            return ret;
        }
        int compose_list_data( typename T::LIST * pList )
        {
            int ret = 0;
            for( typename T::ITER iter = pList->begin(); ( 0 == ret ) && ( iter != pList->end() ); ++iter )
            {
                T * pT = *iter;
                ret = pack_data( pT );
            }
            return ret;
        }
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int un_pack_list_info()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::un_pack_int32( &total_num );
            }
            if( 0 == ret )
            {
                ret = BASE::un_pack_int16( &this_num );
            }
            return ret;
        }
        int pack_list_info()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::pack_int32( total_num );
            }
            if( 0 == ret )
            {
                ret = BASE::pack_int16( this_num );
            }
            return ret;
        }
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int un_pack_this_num()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::un_pack_int16( &this_num );
            }
            return ret;
        }
        int pack_this_num()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::pack_int16( this_num );
            }
            return ret;
        }
    public:
        //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 
        int un_pack_data( T * pT )
        {
            int ret = 0;
            PACKER pkg( BASE::m_pSerial, BASE::m_pBuf );
            if( 0 == ret )
            {
                ret = pT->clear_use();
            }
            for( xos::xos_u8 i = 0; ( 0 == ret ) && ( i < field_num ); ++i )
            {
                if( 0 == ret )
                {
                    ret = pkg.un_pack( fields[i], pT );
                }
                if( 0 == ret )
                {
                    pT->set_use( fields[i], true );
                }
            }
            return ret;
        }
        int pack_data( T * pT )
        {
            int ret = 0;
            PACKER pkg( BASE::m_pSerial, BASE::m_pBuf );
            for( xos::xos_u8 i = 0; ( 0 == ret ) && ( i < field_num ); ++i )
            {
                ret = pkg.pack( fields[i], pT );
            }
            return ret;
        }
    };

}

#endif // __XOSKIT_XOS_CORE_XOS_STL_SRC_PROTOCOL_IMPL_PROTOCOL_FIELD_H__
